﻿using Framework.Common.Paged;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace Framework.Common
{
    public static class LinqExpress
    {
        #region 动态排序扩展
        /// <summary>
        /// 动态排序扩展
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="propertyName">排序字段</param>
        /// <param name="orderType">排序方式 升序 降序</param>
        /// <returns></returns>
        public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName, string orderType) where T : class
        {
            Type type = typeof(T);
            PropertyInfo property = type.GetProperty(propertyName);
            if (property == null)
                throw new ArgumentException("propertyName", "Not Exist");
            ParameterExpression param = Expression.Parameter(type, "p");
            Expression propertyAccessExpression = Expression.MakeMemberAccess(param, property);
            LambdaExpression orderByExpression = Expression.Lambda(propertyAccessExpression, param);
            string methodName = orderType.ToLower() == "asc" ? "OrderBy" : "OrderByDescending";
            MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName, new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExpression));
            return source.Provider.CreateQuery<T>(resultExp);

        }
        /// <summary>
        /// 动态后续排序扩展
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="propertyName">排序字段</param>
        /// <param name="orderType">排序方式 升序 降序</param>
        /// <returns></returns>
        public static IQueryable<T> ThenBy<T>(this IQueryable<T> source, string propertyName, string orderType) where T : class
        {
            Type type = typeof(T);
            PropertyInfo property = type.GetProperty(propertyName);
            if (property == null)
                throw new ArgumentException("propertyName", "Not Exist");
            ParameterExpression param = Expression.Parameter(type, "p");
            Expression propertyAccessExpression = Expression.MakeMemberAccess(param, property);
            LambdaExpression orderByExpression = Expression.Lambda(propertyAccessExpression, param);
            string methodName = orderType.ToLower() == "asc" ? "ThenBy" : "ThenByDescending";
            MethodCallExpression resultExp = Expression.Call(typeof(Queryable), methodName, new Type[] { type, property.PropertyType }, source.Expression, Expression.Quote(orderByExpression));
            return source.Provider.CreateQuery<T>(resultExp);
        }
        #endregion
        /// <summary>
        /// 动态排序扩展
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="propertyName">排序字段</param>
        /// <param name="orderType">排序方式 升序 降序</param>
        /// <returns></returns>
        public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, List<KeyValuePair<string, string>> SortField) where T : class
        {
            for (int i = 0; i < SortField.Count; i++)
            {
                if (i == 0)
                {
                    source = source.OrderBy(SortField[i].Key, SortField[i].Value);
                }
                else
                {
                    source = source.ThenBy(SortField[i].Key, SortField[i].Value);
                }

            }
            return source;
        }


        #region 分页
        /// <summary>
        /// 分页扩展
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source">源</param>
        /// <param name="pageNo">当前页码</param>
        /// <param name="pageSize">页大小</param>
        /// <param name="predicateFunc">条件处理</param>
        /// <param name="sortField">排序字段</param>
        /// <returns></returns>
        public static CustomPagedList<T> GetPagedList<T>(this IQueryable<T> source, int pageNo, int pageSize,
            Func<IQueryable<T>, IQueryable<T>> predicateFunc,
            List<KeyValuePair<string, string>> sortField) where T : class
        {
            if (sortField == null || !sortField.Any()) throw new Exception("sortField is null");
            return predicateFunc(source).OrderBy(sortField).ToStaticPagedList(pageNo, pageSize);
        }
        public static IEnumerable<TTo> ToMapList<TFrom, TTo>(this IEnumerable<TFrom> source, Func<TFrom, TTo> converter)
        {
            return source.Select(converter);
        }
        #endregion
    }
}
